package com.zjitc.book.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zjitc.book.common.result.R;
import com.zjitc.book.filter.JwtFilter;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@Slf4j
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Autowired
    JwtFilter jwtFilter;

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf(csrf->csrf.disable())
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .exceptionHandling(exception->{
                    exception.accessDeniedHandler(accessDeniedHandler())
                            .authenticationEntryPoint(authenticationEntryPoint());
                })
                .authorizeHttpRequests(auth->
                        auth
                                .requestMatchers("/api/auth/login","/api/auth/register").permitAll()
//                                .anyRequest().permitAll()
                                .anyRequest().authenticated()
//                                .requestMatchers("/api/**").permitAll()
                )
                .sessionManagement(session->session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
        return httpSecurity.build();
    }

    @Bean
    BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOriginPattern("*");//允许的域名
        corsConfiguration.addAllowedMethod("*");//允许的HTTP方法
        corsConfiguration.addAllowedHeader("*");//允许的请求头
        corsConfiguration.setAllowCredentials(true);//允许凭证
        corsConfiguration.setMaxAge(3600L);//允许缓存时间

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);//应用到所有路径
        return source;
    }

//    private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);请求响应
    // 定义一个认证错误处理器
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint(){

        return (request, response, authException) -> {
            // log.warn()记录警告级别日志
            log.warn("认证失败:{}{}",request.getRequestURI(),authException.getMessage());
            // 响应内容类型
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            // 设置HTTP状态码为401未授权
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            // 获取HTTP响应输出流再将将Java对象序列化为JSON
            new ObjectMapper().writeValue(response.getOutputStream(), R.error("认证失败:"+authException.getMessage()));
        };
    }

    // 授权错误处理器
    @Bean
    public AccessDeniedHandler accessDeniedHandler(){
        return (request, response, accessDeniedException) ->{
            // log.warn()记录警告级别日志
            log.warn("授权失败:{}{}",request.getRequestURI(),accessDeniedException.getMessage());
            // 响应内容类型
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            // 设置HTTP状态码为401未授权
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            // 获取HTTP响应输出流再将将Java对象序列化为JSON
            new ObjectMapper().writeValue(response.getOutputStream(), R.error("权限不足:"+accessDeniedException.getMessage()));

        };
    }
}
